<?php
namespace Pub;
/**
 * 列表树生成工具类
 */
class Tree{

    private $formatTree = [];
    public $pidName = "pid";  
    public $titleName = "name";
    public $childName = "children";
    public $rootId = 0;
    public $filter = [];  //要剔除掉的字段
    public $strict = true; //严格模式
    public $title_prefix = "┝ ";
    public $expandLevel = 0;


    function listToTree($list, $pid=0, $level=1 )
    {
        $temp = array();
        foreach ($list as $k => $v) {
            if($v[$this->pidName] == $pid){
                $v['level'] = $level;
                $v[$this->childName] = $this->listToTree($list, $v['id'], $level+1);
                if(!$v[$this->childName])unset($v[$this->childName]);
                $temp[] = $v;
            }
        }
        return $temp;
    }

    public function toFormatTree($list, $pid=0, $level=1)
    {
        $temp = array();
        foreach ($list as $k => $val) {
            if($val[$this->pidName] == $pid){
                $title_pre = str_repeat("　", ($level-1)*1); //&nbsp;
                $title_pre .= $this->title_prefix;
                $val['level'] = $level;
                //$val['title_prefix'] = $level == 0 ? '' : $title_prefix;
                $val['_title'] = $level == 0 ? $val[$this->titleName] : $title_pre.$val[$this->titleName];
                $temp[] = $val;
                $temp = array_merge($temp,$this->toFormatTree($list,$val['id'],$level+1));
            }
        }
        return $temp;
    }

    /**
     * 将list_to_tree的树还原成列表
     * @param    array $tree    原来的树
     * @param    string $order 排序显示的键，一般是主键 升序排列
     * @param    array $list 过渡用的中间数组，
     * @return array 返回排过序的列表数组
     */
    public function treeToList($tree, $order='id', &$list = array()){
        if(is_array($tree)){
            foreach ($tree as $key => $value){
                $reffer = $value;
                if(isset($reffer[$this->childName])){
                    unset($reffer[$this->childName]);
                    this.treeToList($value[$this->childName], $order, $list);
                }
                $list[] = $reffer;
            }
            $list = $this->list_sort_by($list, $order, $sortby='asc');
        }
        return $list;
    }

    /**
    * 对查询结果集进行排序
    * @access public
    * @param array $list 查询结果
    * @param string $field 排序的字段名
    * @param array $sortby 排序类型 asc正向排序 desc逆向排序 nat自然排序
    * @return array
    */
    public function list_sort_by($list, $field, $sortby='asc'){
        if(is_array($list)){
            $refer = $resultSet = array();
            foreach($list as $i => $data)
                $refer[$i] = &$data[$field];
            switch($sortby){
                case 'asc': // 正向排序
                    asort($refer);
                    break;
                case 'desc':// 逆向排序
                    arsort($refer);
                    break;
                case 'nat': // 自然排序
                    natcasesort($refer);
                    break;
            }
            foreach ($refer as $key=> $val)
                $resultSet[] = &$list[$key];
            return $resultSet;
        }
        return false;
    }

    /**
     * 在数据列表中搜索
     * @access public
     * @param array $list 数据列表
     * @param mixed $condition 查询条件
     * 支持 array('name'=>$value) 或者 name=$value
     * @return array
     */
    function list_search($list,$condition){
        if(is_string($condition))
            parse_str($condition, $condition);
            //返回的结果集合
            $resultSet = array();
            foreach ($list as $key => $data){
                $find = false;
                foreach ($condition as $field=>$value){
                    if(isset($data[$field])){
                        if(0 === strpos($value,'/')){
                            $find = preg_match($value,$data[$field]);
                        }elseif($data[$field]==$value){
                            $find = true;
                        }
                    }
                }
            if($find){
                $resultSet[] = &$list[$key];
            }
        }
        return $resultSet;
    }

    /**
     * 获取 所有直接子项
     */
    public function getchild($bid){
        $a = $newarr = array();
        if(is_array($this->arr)){
            foreach($this->arr as $id => $a){
                if($a['pid'] == $bid) $newarr[$id] = $a;
            }
        }
        return $newarr ? $newarr : false;
    }

    /** 返回 "1,2,3" 或 "name1/name2/name3..."
     * 
     */
    public function getParentPath($list, $id, $field="id", $split = ",")
    {
        $rsList = $this->getParentArr($list,$id);
        $arr = [];
        foreach ($rsList as $k => $v) {
            $arr[] = $v[$field];
        }
        return join($split, $arr);
    }

    /** 返回 [[id:1, name=>aa], [id:2, name=>bb]]
     * 
     */
    public function getParentArr($list, $id)
    {
        $this->_getParentPath($list, $id);
        if($this->formatTree){
            array_shift($this->formatTree);
            $this->formatTree = array_reverse($this->formatTree);
        }
        return $this->formatTree;
    }

    /**
     * 获取所有父级信息
     */
    private function _getParentPath($list, $id)
    {
        foreach($list as $key=>$val){
            if($id==0){
                return;
            }elseif($val['id']==$id){
                $pid = $val['pid'];
                array_push($this->formatTree, $val);
                $this->_getParentPath($list,$pid); 
            }
        }
        
        return $this->formatTree;
    }



    /**
    * 将格式数组转换为基于标题的树（实际还是列表，只是通过在相应字段加前缀实现类似树状结构）
    * @param array $list
    * @param integer $level 进行递归时传递用的参数
    */
    private function _toFormatTree($list, $level = 0){
        foreach($list as $key=>$val){
            $title_prefix = str_repeat("&nbsp;", $level*4);
            $title_prefix .= "┝ ";
            $val['level'] = $level;
            $val['title_prefix'] = $level == 0 ? '' : $title_prefix;
            $val['title_show'] = $level == 0 ? $val[$title] : $title_prefix.$val[$title];
            if(!array_key_exists($this->$childName, $val)){
                array_push($this->formatTree, $val);
            }else{
                $child = $val[$this->$childName];
                unset($val[$this->$childName]);
                array_push($this->formatTree, $val);
                $this->_toFormatTree($child, $level+1); //进行下一层递归
            }
        }
        return;
    }

    /**
    * 将格式数组转换为树  (树形的列)
    * @param array $list
    * @param integer $level 进行递归时传递用的参数
    */
    public function toFormatTree2($list){
        $list = $this->list_to_tree($list);
        $this->formatTree = array();
        $this->_toFormatTree($list, 0);
        return $this->formatTree;
    }

    /**
     * 将数据集转换成Tree（真正的Tree结构）带 child
     * @param array $list 要转换的数据集
     */
    public function listToTree2($list){
        // 创建Tree
        $tree = array();
        if(is_array($list)){
            // 创建基于主键的数组引用
            $refer = array();
            foreach($list as $key => $data){
                $refer[$data["id"]] =& $list[$key];
            }
            foreach($list as $key => $data){
                // 判断是否存在parent
                $parent_id = $data[$this->pidName];
                if($parent_id === null || (int)$this->rootId === $parent_id){
                    $tree[] =& $list[$key];
                }else{
                    if(isset($refer[$parent_id])){
                        $parent =& $refer[$parent_id];
                        $parent[$this->childName][] =& $list[$key];
                    }else{
                        if($this->strict === false){
                            $tree[] =& $list[$key];
                        }
                    }
                }
            }
            //剔除数据
            if(count($this->filter) > 0){
                foreach($refer as $key => $data){
                    foreach ($data as $k => $v) {
                        if(in_array($k, $this->filter)) unset($refer[$key][$k]);
                    }
                }
            }
        }
        return $tree;
    }
}
